<?php
namespace app\admin\controller;

/**
 * 升级
 * TODO 更换api
 */
class Upgrade extends \app\admin\controller\Common
{

    public function index()
    {
        if (request()->isGet()) {
            $this->success('', '', $this->fetch());
        } elseif (request()->isPost()) {
            $ver = include CONF_PATH . 'version.php';
            $param = [
                'version' => $ver['version'],
                'page' => input('page'),
                'rows' => input('rows'),
            ];
            // $res = \ebcms\Server::api('version_all', $param);
            $res = array();
            if ($res['code']) {
                $this->success($res['msg'], '', $res['data']);
            } else {
                $this->error($res['msg'], '', $res['data']);
            }
        }
    }

    // 更新数据库

    public function upgrade()
    {
        $ver = include CONF_PATH . 'version.php';
        $param = [
            'version' => $ver['version'],
        ];
        // $res = \ebcms\Server::api('version_next', $param);
        $res = array();
        if (!$res['code']) {
            $this->error($res['msg'], '', $res['data']);
        }
        $res = $res['data'];
        $patch_path = \ebcms\Config::get('system.backup_path') . DS . 'patch' . DS;
        $file_path = \ebcms\Config::get('system.backup_path') . DS . 'file' . DS;
        if (request()->isGet()) {
            if (!is_dir($patch_path)) {
                if (is_writable(dirname($patch_path))) {
                    mkdir($patch_path, 0755, true);
                } else {
                    $this->error('无法创建文件夹，请检查' . dirname($patch_path) . '的权限！');
                }
            } elseif (!is_writable($patch_path)) {
                $this->error($patch_path . '文件夹不存在或权限不足！请修改！');
            }
            if (!is_dir($file_path)) {
                if (is_writable(dirname($file_path))) {
                    mkdir($file_path, 0755, true);
                } else {
                    $this->error('无法创建文件夹，请检查' . dirname($file_path) . '的权限！');
                }
            } elseif (!is_writable($file_path)) {
                $this->error($file_path . '文件夹不存在或权限不足！请修改！');
            }
            if ($res['file']) {
                $filename = $patch_path . 'ebcms_patch_v' . $res['version'] . '.zip';
                if (!is_file($filename) || $res['file_md5'] != md5(file_get_contents($filename))) {
                    $downfile = file_get_contents($res['file']);
                    if ($res['file_md5'] != md5($downfile)) {
                        $this->error('文件校验失败！请重新下载！');
                    }
                    if (is_file($filename) && !is_writable($filename)) {
                        $this->error($filename . '文件已经存在！请修改该文件权限！');
                    }
                    file_put_contents($filename, $downfile);
                }
                $files = [];
                $errors = [];
                $this->checkzip($filename, $files, $errors);
                $this->assign('files', $files);
                $this->assign('error', $errors ? 1 : 0);
                $this->assign('errors', array_unique($errors));
            }
            if ($res['exec']) {
                $execfile = $patch_path . 'ebcms_patch_v' . $res['version'] . '.php';
                if (!is_file($execfile) || $res['file_md5'] != md5(file_get_contents($execfile))) {
                    $downfile = file_get_contents($res['exec']);
                    if ($res['exec_md5'] != md5($downfile)) {
                        $this->error('文件校验失败！请重新下载！');
                    }
                    if (is_file($execfile) && !is_writable($execfile)) {
                        $this->error($execfile . '文件已经存在但无法修改！请修改该文件权限！');
                    }
                    file_put_contents($execfile, $downfile);
                }
                $this->assign('exec', 1);
            }
            $this->assign('res', $res);
            $this->success('', '', $this->fetch());
        } elseif (request()->isPost()) {
            // 更新文件
            if ($res['file']) {
                $filename = $patch_path . 'ebcms_patch_v' . $res['version'] . '.zip';
                $files = [];
                $errors = [];
                $this->checkzip($filename, $files, $errors);
                if ($errors) {
                    $this->error('文件权限校验失败！');
                }
                // 备份文件
                $backup_path = $file_path . $ver['version'] . DS;

                $this->backup_files($files, $backup_path);
                // 更新文件
                $this->update_files($filename);
            }
            // 执行sql
            if ($res['exec']) {
                $execname = $patch_path . 'ebcms_patch_v' . $res['version'] . '.php';
                include $execname;
                if (function_exists('ebcms_upgrade')) {
                    if (true !== $info = ebcms_upgrade()) {
                        $this->error($info);
                    }
                }
            }
            $this->success('更新成功！');
        }
    }

    // 检查权限
    private function checkzip($filename, &$files, &$errors)
    {
        $rs = zip_open($filename);
        while ($dir_rs = zip_read($rs)) {
            if (zip_entry_open($rs, $dir_rs)) {
                $file = zip_entry_name($dir_rs);
                if (0 === strpos($file, 'public')) {
                    $pathfile = '.' . substr($file, 6);
                } else {
                    $pathfile = ROOT_PATH . $file;
                }
                if (pathinfo($pathfile, PATHINFO_EXTENSION)) {
                    if (is_file($pathfile)) {
                        if (is_writable($pathfile)) {
                            $files[$file] = true;
                        } else {
                            $errors[] = $pathfile;
                            $files[$file] = false;
                        }
                    } else {
                        $files[$file] = $this->checkpath(dirname($pathfile), $errors);
                    }
                }
                zip_entry_close($dir_rs);
            }
        }
        zip_close($rs);
    }

    private function checkpath($path, &$errors)
    {
        if (is_dir($path)) {
            if (is_writable($path)) {
                return true;
            } else {
                $errors[] = $path;
                return false;
            }
        } else {
            return $this->checkpath(dirname($path), $errors);
        }
    }

    private function update_files($filename)
    {
        $rs = zip_open($filename);
        while ($dir_rs = zip_read($rs)) {
            if (zip_entry_open($rs, $dir_rs)) {
                $file = zip_entry_name($dir_rs);
                $file_size = zip_entry_filesize($dir_rs);
                if (0 === strpos($file, 'public')) {
                    $filename = '.' . substr($file, 6);
                } else {
                    $filename = ROOT_PATH . $file;
                }
                if (pathinfo($filename, PATHINFO_EXTENSION)) {
                    $file_size = zip_entry_filesize($dir_rs);
                    $file_content = zip_entry_read($dir_rs, $file_size);
                    file_put_contents($filename, $file_content);
                } else {
                    if (!is_dir($filename)) {
                        mkdir($filename, 0755, true);
                    }
                }
                zip_entry_close($dir_rs);
            }
        }
        zip_close($rs);
        return true;
    }

    private function backup_files($files, $path)
    {
        if (!is_dir($path)) {
            mkdir($path, 0755, true);
        }
        foreach ($files as $file => $v) {
            if (0 === strpos($file, 'public')) {
                $filename = '.' . substr($file, 6);
            } else {
                $filename = ROOT_PATH . $file;
            }
            if (is_file($filename)) {
                $backfile = str_ireplace(['/', '\\'], '____', $file);
                file_put_contents($path . $backfile . '.php', file_get_contents($filename));
            }
        }
    }
}